/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   UdpPacket.h
 * Author: everpan
 *
 * Created on 2018年11月6日, 下午10:08
 */

#ifndef UDPPACKET_H
#define UDPPACKET_H


#include "config.h"

#define TIMESTAMP_2000  946656000LL

namespace pr {

    typedef unsigned long long u64;

    class UdpPacket {
    public:

        struct Head {
            char P;
            char R;
            u8_t ver;
            u8_t cmd;
            u8_t sno;
            u8_t pno[4];
            u8_t date[4];
            u8_t len[2];

            u8_t getVer() const;

            u64 getTime();

            void setTime();

            u32_t getPackageNo();

            void setPackageNo();

            u32_t getBodyLength();

            void setBodyLength();

            u8_t getSNo();
            u16_t getFNo() const;
        } __attribute__ ((aligned(1)));

        struct Head2 {
            char P;
            char R;
            u8_t ver;
            u8_t cmd;
            u8_t fno[2];
            u8_t sno;
            u8_t pno[4];
            u8_t date[4];
            u8_t len[2];
        } __attribute__ ((aligned(1)));


        struct TGN {
            u8_t tagId[3];
            u8_t tagVal[4];
            u8_t quality;

            u32_t getTagId();

            void setTagId(u32_t id);

            float getValue();

            void setValue(float v);

            char getQuality();

            void setQuality(u8_t q);
        } __attribute__ ((aligned(1)));

        UdpPacket();

        UdpPacket(const UdpPacket &orig);

        virtual ~UdpPacket();


        void setData(u8_t *data, int len);

        u16_t getCmd();

        Head *getHead();

        TGN *getTGN();

        bool isValid();

        bool hasNext();

        u32_t getNum();


        inline static u32_t From2ByteToU32(u8_t *);

        inline static u32_t From3ByteToU32(u8_t *);

        inline static u32_t From4ByteToU32(u8_t *);

        inline static void PackU32(u32_t v, u8_t *data);

        inline static void PackU24(u32_t v, u8_t *data);

        inline static void PackU16(u16_t v, u8_t *data);

    private:
        u8_t *_data;
        int _len;
        //inner cache
        bool _isValid = false;
        long long _date;
        Head *_head;
        u32_t _package_count = 0;
    };

    u32_t UdpPacket::From2ByteToU32(u8_t *v) {
        return (v[0] << 8) | (v[1]);
    }

    u32_t UdpPacket::From3ByteToU32(u8_t *v) {
        return (v[0] << 16) | (v[1] << 8) | (v[2]);
    }

    u32_t UdpPacket::From4ByteToU32(u8_t *v) {
        return (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | (v[3]);
    }

    void UdpPacket::PackU32(u32_t v, u8_t *data) {
#ifdef BIGENDIAN
        *(u32_t*) (data) = v;
#else
        u8_t *p = (u8_t *) (&v);
        data[0] = p[3];
        data[1] = p[2];
        data[2] = p[1];
        data[3] = p[0];
#endif
    }

    void UdpPacket::PackU24(u32_t v, u8_t *data) {
#ifdef BIGENDIAN
        u8_t * p = (u8_t *) (&v);
        data[0] = p[0];
        data[1] = p[1];
        data[2] = p[2];
#else
        u8_t *p = (u8_t *) (&v);
        data[0] = p[2];
        data[1] = p[1];
        data[2] = p[0];
#endif
    }

    void UdpPacket::PackU16(u16_t v, u8_t *data) {
#ifdef BIGENDIAN
        *(u16_t*) (data) = v;
#else
        u16_t *p = (u16_t *) (&v);
        data[0] = p[1];
        data[1] = p[0];
#endif
    }


}


#endif /* UDPPACKET_H */

